package com.iwdnb.gkgz.application.strategy;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import cn.hutool.core.date.DateUtil;
import com.iwdnb.gkgz.application.model.request.AddStrategyTradeStockDataRequest;
import com.iwdnb.gkgz.common.enums.TrendTypeEnums;
import com.iwdnb.gkgz.common.model.dto.StockDayData;
import com.iwdnb.gkgz.common.model.dto.StockRangeScopeDTO;
import com.iwdnb.gkgz.common.model.dto.StrategyTradeDTO;
import com.iwdnb.gkgz.common.quota.MovingAverage;
import com.iwdnb.gkgz.common.utils.BigDecimalUtils;
import com.iwdnb.gkgz.common.utils.DateUtils;
import com.iwdnb.gkgz.common.utils.StockUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import static com.iwdnb.gkgz.common.utils.StockUtils.getAveragePrice;
import static com.iwdnb.gkgz.common.utils.StockUtils.isFirstLimitUp;

/**
 * 黯然销魂涨
 */
@Service
@Slf4j
public class FirstLimitUpStockBackValidateService extends CommmonStockBackValidateService {

    private static final String STATEGY_CODE = "firstLimitUp";

    private static final String SUMMARY
        = "当日60日均价=%s,开盘价=%s,收盘价=%s,60日均线对比:%s-%s-%s,60走势:%s,30日均线对比:%s-%s-%s,30走势:%s,40天均线:%s-%s,20天均线:%s-%s,"
        + "10天均线:%s-%s";

    @Override
    public List<StrategyTradeDTO> queryBackValidateDateList(String code, String strategy,
        List<StockDayData> stockDayDataList,
        AddStrategyTradeStockDataRequest request) {
        int sixtyPeriod = 60;
        int thirtyPeriod = 30;

        MovingAverage.calculateEMA(stockDayDataList, 20);
        MovingAverage.calculateEMA(stockDayDataList, 30);
        MovingAverage.calculateEMA(stockDayDataList, 60);
        List<String> dateList = new ArrayList<>();
        List<StrategyTradeDTO> strategyTradeDTOList = new ArrayList<>();
        for (int i = 0; i < stockDayDataList.size(); i++) {
            if (i < 80) {
                continue;
            }
            StockDayData data = stockDayDataList.get(i);
            StockDayData yesterdayData = stockDayDataList.get(i - 1);
            if (BigDecimalUtils.isLe(data.getOpenPrice(), BigDecimal.ONE)) {
                continue;
            }
            String date = data.getDate();
            //不是首板涨停，跳过
            if (!isFirstLimitUp(data, stockDayDataList, 10)) {
                //log.debug("不是首板涨停，跳过");
                continue;
            }
            BigDecimal openPrice = stockDayDataList.get(i - 1).getClosePrice();
            List<StockDayData> afterDayDataList = StockUtils.getStockDayDataListAfterDate(stockDayDataList, date, 15);
            if (CollectionUtils.isEmpty(afterDayDataList) || afterDayDataList.size() < 3) {
                //log.debug("{}-{}-未找到未来2天的数据，跳过", code, date);
                continue;
            }
            StockDayData afterOneDayData = afterDayDataList.get(0);
            ////红绿灯，绿灯，跳过
            //if (!RedGreenLightUtils.isAvailable(afterOneDayData.getDate())) {
            //    continue;
            //}
            ////最高价比涨停日价格小2个点以下，跳过
            //BigDecimal oneMaxDayRange = afterOneDayData.getMaxPrice().subtract(data.getMaxPrice());
            //BigDecimal oneMaxDayRate = BigDecimalUtils.divideToPrecent(oneMaxDayRange, data.getMaxPrice());
            //if (BigDecimalUtils.isLt(oneMaxDayRate, new BigDecimal(2))) {
            //    continue;
            //}
            BigDecimal sixtyAvg = getAveragePrice(data, sixtyPeriod);
            BigDecimal thirtyAvg = getAveragePrice(data, thirtyPeriod);
            List<StockDayData> beforeFourtyDayDatas = StockUtils.getStockDayDataListBeforeDate(stockDayDataList,
                date, 40);
            StockDayData beforeFourtyData = beforeFourtyDayDatas.get(0);
            StockDayData beforeTwentyData = beforeFourtyDayDatas.get(20);
            StockDayData beforeTenData = beforeFourtyDayDatas.get(30);

            BigDecimal beforeFourtyAvg = getAveragePrice(beforeFourtyData, sixtyPeriod);
            BigDecimal beforeFourtyRate = BigDecimalUtils.subStractAndDividePrecent(beforeFourtyAvg, sixtyAvg);
            BigDecimal beforeTwentyAvg = getAveragePrice(beforeTwentyData, sixtyPeriod);
            BigDecimal beforeTwentyRate = BigDecimalUtils.subStractAndDividePrecent(beforeTwentyAvg, sixtyAvg);
            BigDecimal beforeTenAvg = getAveragePrice(beforeTenData, sixtyPeriod);
            BigDecimal beforeTenRate = BigDecimalUtils.subStractAndDividePrecent(beforeTenAvg, sixtyAvg);
            BigDecimal beforeFourtyThirtyAvg = getAveragePrice(beforeFourtyData, thirtyPeriod);
            BigDecimal beforeFourtyThirtyRate = BigDecimalUtils.subStractAndDividePrecent(beforeFourtyThirtyAvg,
                thirtyAvg);
            BigDecimal beforeTwentyThirtyAvg = getAveragePrice(beforeTwentyData, thirtyPeriod);
            BigDecimal beforeTwentyThirtyRate = BigDecimalUtils.subStractAndDividePrecent(beforeTwentyThirtyAvg,
                thirtyAvg);
            BigDecimal beforeTenThirtyAvg = getAveragePrice(beforeTenData, thirtyPeriod);
            BigDecimal beforeTenThirtyRate = BigDecimalUtils.subStractAndDividePrecent(beforeTenThirtyAvg, thirtyAvg);
            TrendTypeEnums sixtyTrend = TrendTypeEnums.getTrendType(beforeFourtyAvg, beforeTwentyAvg, beforeTenAvg,
                sixtyAvg);
            TrendTypeEnums thirtyTrend = TrendTypeEnums.getTrendType(beforeFourtyThirtyAvg, beforeTwentyThirtyAvg,
                beforeTenThirtyAvg, thirtyAvg);

            ////40日前的60日均价比当天低50%以上，跳过
            //if (BigDecimalUtils.isLt(beforeFourtyRate, new BigDecimal(-50))) {
            //    continue;
            //}
            BigDecimal yesterdayClosePrice = yesterdayData.getClosePrice();
            BigDecimal minPrice = data.getMinPrice();
            minPrice = BigDecimalUtils.isLt(minPrice, yesterdayClosePrice) ? minPrice : yesterdayClosePrice;
            //过滤出买点日期
            int signalDayIndex = filterSignalDayIndex(afterDayDataList, data, minPrice);
            if (signalDayIndex <= 0) {
                continue;
            }
            StockDayData buyDayData = filterMatchDay(afterDayDataList, data, minPrice, signalDayIndex);
            if (Objects.isNull(buyDayData)) {
                continue;
            }

            ////涨停日收盘价在60日均价下方，跳过
            //BigDecimal openPriceUpSeven = data.getOpenPrice().multiply(new BigDecimal(1.07));
            //if (BigDecimalUtils.isLt(openPriceUpSeven, sixtyAvg)) {
            //    //log.debug("{}-{}-涨停日开盘价在60日均价下方，跳过", code, date);
            //    continue;
            //}
            //BigDecimal beforeThiryMaxPrice = StockUtils.getMaxPriceBeforeDate(stockDayDataList, date, 30);
            //BigDecimal beforeThiryMaxRate = BigDecimalUtils.subStractAndDividePrecent(beforeThiryMaxPrice,
            //    data.getClosePrice());
            //if (BigDecimalUtils.isGt(beforeThiryMaxRate, new BigDecimal(6))) {
            //    //log.debug("{}-{}-涨停日之前有高点，跳过", code, date);
            //    continue;
            //}
            //涨停日前一工作日涨了超过6个点，跳过
            //StockDayData yesterdayStockDayData = StockUtils.getYesterdayStockDayData(stockDayDataList, date);
            //if (BigDecimalUtils.isGt(yesterdayStockDayData.getRate(), new BigDecimal(6))) {
            //    //log.debug("{}-{}-涨停日前一工作日涨了超过6个点，跳过", code, date);
            //    continue;
            //}
            ////涨停日10个工作日涨了超过25个点，跳过
            //BigDecimal beforeTenLowPrice = StockUtils.getMinPriceBeforeDate(stockDayDataList, date, 10);
            //BigDecimal beforeTenLowRate = BigDecimalUtils.subStractAndDividePrecent(data.getClosePrice(),
            //    beforeTenLowPrice);
            //if (BigDecimalUtils.isGt(beforeTenLowRate, new BigDecimal(25))) {
            //    //log.debug("{}-{}-涨停日10个工作日涨了超过25个点，跳过", code, date);
            //    continue;
            //}
            //涨停日比2个月内的最低价高50%，跳过
            String beginDate = DateUtil.formatDate(DateUtil.offsetDay(DateUtil.parseDate(date), -22));
            StockRangeScopeDTO rangeScopeDTO = StockUtils.getRangeScopeByDateRange(stockDayDataList, beginDate, date);
            BigDecimal lowRate = BigDecimalUtils.subStractAndDividePrecent(data.getClosePrice(),
                rangeScopeDTO.getLowPrice());
            //log.debug("{}-{}-50日内的最低价差={}", code, date, lowRate);
            if (BigDecimalUtils.isGt(lowRate, new BigDecimal(30))) {
                continue;
            }

            String afterTwoDate = buyDayData.getDate();
            if (!dateList.contains(afterTwoDate)) {
                dateList.add(afterTwoDate);
                StrategyTradeDTO strategyTradeDTO = new StrategyTradeDTO();
                strategyTradeDTO.setCode(code);
                strategyTradeDTO.setUuid(STATEGY_CODE);
                strategyTradeDTO.setBuyDate(DateUtil.parseDate(afterTwoDate));
                strategyTradeDTO.setBuyPrice(buyDayData.getClosePrice());
                strategyTradeDTO.setStatus("buy");

                String summary = String.format(SUMMARY, sixtyAvg.toString(), data.getOpenPrice().toString(),
                    data.getClosePrice().toString(),
                    beforeFourtyRate, beforeTwentyRate, beforeTenRate, sixtyTrend.getCode(),
                    beforeFourtyThirtyRate, beforeTwentyThirtyRate, beforeTenThirtyRate, thirtyTrend.getCode(),
                    beforeFourtyAvg, beforeFourtyThirtyAvg,
                    beforeTwentyAvg, beforeTwentyThirtyAvg,
                    beforeTenAvg, beforeTenThirtyAvg
                );
                strategyTradeDTO.setSummary(summary);
                strategyTradeDTO.setRealtimePrice(minPrice.multiply(new BigDecimal(0.99)));
                strategyTradeDTOList.add(strategyTradeDTO);
                //caculateAfterDaysProfit(code, afterTwoDate, stockDayDataList, 10);

            }
        }
        return strategyTradeDTOList;
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void doBackValidate(String code, String strategy, List<StockDayData> stockDayDataList,
        List<StrategyTradeDTO> strategyTradeDTOList) {
        List<String> dateList = strategyTradeDTOList.stream().map(o -> DateUtil.formatDate(o.getBuyDate())).collect(
            Collectors.toList());
        Date latestEndDate = DateUtil.parseDate(dateList.get(0));
        latestEndDate = DateUtil.offsetDay(latestEndDate, -1);
        for (StrategyTradeDTO strategyTradeDTO : strategyTradeDTOList) {
            Date d = strategyTradeDTO.getBuyDate();
            if (DateUtils.beforeOrEquals(d, latestEndDate)) {
                log.debug("{}-{}在上一个周期内,忽略", code, d);
                continue;
            }
            getTradeInfo(code, stockDayDataList, strategyTradeDTO);
            latestEndDate = strategyTradeDTO.getSellDate();
        }
    }

    private void getTradeInfo(String code, List<StockDayData> stockDayDataList, StrategyTradeDTO strategyTradeDTO) {
        String date = DateUtil.formatDate(strategyTradeDTO.getBuyDate());
        //log.debug("{}-{}>>>>>股票信息:{}", code, date, strategyTradeDTO.getSummary());
        StockDayData buyDayData = StockUtils.getStockDayData(stockDayDataList, date);
        BigDecimal buyPrice = buyDayData.getClosePrice();
        int size = 30;
        List<StockDayData> subList = StockUtils.getStockDayDataListAfterDate(stockDayDataList, date, size);
        if (CollectionUtils.isEmpty(subList) || subList.size() < size) {
            return;
        }
        BigDecimal closeRate = null;
        String sellDate = null;
        String info = "";
        BigDecimal sellPrice = null;
        BigDecimal rate = closeRate;
        int holdIndex = 0;
        BigDecimal rangeMaxPrice = strategyTradeDTO.getBuyPrice();
        BigDecimal rangeMaxRate = BigDecimal.ZERO;
        BigDecimal rangeCloseMaxPrice = strategyTradeDTO.getBuyPrice();
        BigDecimal rangeCloseMaxRate = BigDecimal.ZERO;
        StockDayData limitUp = null;
        BigDecimal limitPrice = buyPrice;
        BigDecimal minPrice = strategyTradeDTO.getRealtimePrice();
        for (int i = 0; i < size; i++) {
            StockDayData data = subList.get(i);
            StockDayData yesterdayDayData = i == 0 ? data : subList.get(i - 1);
            BigDecimal closePrice = data.getClosePrice();
            closeRate = BigDecimalUtils.subStractAndDividePrecent(closePrice, buyPrice);
            sellDate = data.getDate();
            sellPrice = data.getClosePrice();
            holdIndex = i;
            rangeMaxPrice = BigDecimalUtils.isGt(data.getMaxPrice(), rangeMaxPrice) ? data.getMaxPrice()
                : rangeMaxPrice;
            rangeMaxRate = BigDecimalUtils.subStractAndDividePrecent(rangeMaxPrice, buyPrice);
            rangeCloseMaxPrice = BigDecimalUtils.isGt(data.getClosePrice(), rangeCloseMaxPrice) ? data.getClosePrice()
                : rangeCloseMaxPrice;
            rangeCloseMaxRate = BigDecimalUtils.subStractAndDividePrecent(rangeCloseMaxPrice, buyPrice);
            BigDecimal realtimeRate = BigDecimalUtils.subStractAndDividePrecent(data.getClosePrice(), buyPrice);
            BigDecimal upRange = data.getMaxPrice().subtract(buyPrice);
            BigDecimal upRate = BigDecimalUtils.divideToPrecent(upRange, buyPrice);
            BigDecimal openRange = data.getOpenPrice().subtract(buyPrice);
            BigDecimal openRate = BigDecimalUtils.divideToPrecent(openRange, buyPrice);
            rate = closeRate;
            String sellInfo = "收盘价卖出";
            if (StockUtils.isLimitUp(data)) {
                limitUp = data;
            }
            if (BigDecimalUtils.isGe(realtimeRate, new BigDecimal(120))) {
                Integer yesterdayTradeNumTenTimes = yesterdayDayData.getTradeNum() * 10;
                if (data.getTradeNum() >= yesterdayTradeNumTenTimes) {
                    sellInfo = "出现十倍信号量,止盈";
                    log.debug("第{}天-{}-{}-{}，收益={}，开盘收益={},收盘收益={},最高点收益={}", (i + 1), code, data.getDate(), sellInfo,
                        rate, openRate, closeRate, upRate);
                    info += "第" + (i + 1) + "天" + sellInfo + ",收益=" + rate + ",开盘收益=" + openRate + ",收盘收益=" + closeRate
                        + ",最高点收益=" + upRate;
                    break;
                }
            }
            //50个点以上特殊处理
            if (BigDecimalUtils.isGe(realtimeRate, new BigDecimal(50))) {
                Integer yesterdayTradeNumThreeTimes = yesterdayDayData.getTradeNum() * 3;
                if (data.getTradeNum() >= yesterdayTradeNumThreeTimes && BigDecimalUtils.isLe(data.getRate(),
                    new BigDecimal(-5))) {
                    sellInfo = "出现3倍信号量且暴跌,止盈";
                    log.debug("第{}天-{}-{}-{}，收益={}，开盘收益={},收盘收益={},最高点收益={}", (i + 1), code, data.getDate(), sellInfo,
                        rate, openRate, closeRate, upRate);
                    info += "第" + (i + 1) + "天" + sellInfo + ",收益=" + rate + ",开盘收益=" + openRate + ",收盘收益=" + closeRate
                        + ",最高点收益=" + upRate;
                    break;
                }
            }

            //跌5个点，跑路
            if (BigDecimalUtils.isLt(closeRate, new BigDecimal(-5))) {
                sellInfo = "跌了超过5个点,止损";
                log.debug("第{}天-{}-{}-{}，收益={}，开盘收益={},收盘收益={},最高点收益={}", (i + 1), code, data.getDate(), sellInfo, rate,
                    openRate, closeRate, upRate);
                info += "第" + (i + 1) + "天" + sellInfo + ",收益=" + rate + ",开盘收益=" + openRate + ",收盘收益=" + closeRate
                    + ",最高点收益=" + upRate;
                break;
            }
            //跌破止损价，跑路
            if (BigDecimalUtils.isLt(closePrice, minPrice)) {
                sellInfo = "跌破止损价,止损";
                log.debug("第{}天-{}-{}-{}，收益={}，开盘收益={},收盘收益={},最高点收益={}", (i + 1), code, data.getDate(), sellInfo, rate,
                    openRate, closeRate, upRate);
                info += "第" + (i + 1) + "天" + sellInfo + ",收益=" + rate + ",开盘收益=" + openRate + ",收盘收益=" + closeRate
                    + ",最高点收益=" + upRate;
                break;
            }
            if (Objects.nonNull(limitUp)) {
                limitPrice = limitUp.getMinPrice();
            }
            //连跌3天，如果前面是涨停板就等跌破涨停板低点卖出
            if (BigDecimalUtils.isGe(rangeCloseMaxRate, new BigDecimal(30))) {
                StockDayData twoDayData = subList.get(i - 2);
                //前面有涨停板的话，不能跌破涨停板的
                if (BigDecimalUtils.isLt(data.getClosePrice(), limitPrice) && BigDecimalUtils.isLt(data.getRate(),
                    BigDecimal.ZERO) && BigDecimalUtils.isLt(yesterdayDayData.getRate(), BigDecimal.ZERO)
                    && BigDecimalUtils.isLt(twoDayData.getRate(), BigDecimal.ZERO) && BigDecimalUtils.isLt(
                    data.getClosePrice(), data.getOpenPrice()) && BigDecimalUtils.isLt(yesterdayDayData.getClosePrice(),
                    yesterdayDayData.getOpenPrice()) && BigDecimalUtils.isLt(twoDayData.getClosePrice(),
                    twoDayData.getOpenPrice())) {
                    sellInfo = "连跌3天,止损";
                    log.debug("第{}天-{}-{}-{}，收益={}，开盘收益={},收盘收益={},最高点收益={}", (i + 1), code, data.getDate(), sellInfo,
                        rate, openRate, closeRate, upRate);
                    info += "第" + (i + 1) + "天" + sellInfo + ",收益=" + rate + ",开盘收益=" + openRate + ",收盘收益=" + closeRate
                        + ",最高点收益=" + upRate;
                    break;
                }
            }

            //5天内涨过35个点
            if (i <= 4 && !StockUtils.isLimitUp(data) && BigDecimalUtils.isGe(closeRate, new BigDecimal(35))) {
                sellInfo = "4天涨过30个点,卖掉";
                log.debug("{}-{}-{}，收益={}，开盘收益={},收盘收益={},最高点收益={}", code, data.getDate(), sellInfo, rate, openRate,
                    closeRate, upRate);
                info += "第" + (i + 1) + "天" + sellInfo + ",收益=" + rate + ",开盘收益=" + openRate + ",收盘收益=" + closeRate
                    + ",最高点收益=" + upRate;
                break;
            }
            ////5天还没涨过5个点
            //if (i == 5 && BigDecimalUtils.isLt(closeRate, new BigDecimal(5))) {
            //    sellInfo = "5天没涨过5个点,卖掉";
            //    log.debug("{}-{}-{}，收益={}，开盘收益={},收盘收益={},最高点收益={}", code, data.getDate(), sellInfo, rate, openRate,
            //        closeRate, upRate);
            //    info += "第" + (i + 1) + "天" + sellInfo + ",收益=" + rate + ",开盘收益=" + openRate + ",收盘收益=" + closeRate
            //        + ",最高点收益=" + upRate;
            //    break;
            //}
            //50个点以上，回落超过2成
            if (BigDecimalUtils.isGe(rangeCloseMaxRate, new BigDecimal(50)) && BigDecimalUtils.isGe(
                rangeCloseMaxRate.multiply(new BigDecimal(0.8)), realtimeRate)) {
                sellInfo = "回落2成,止盈";
                log.debug("第{}天-{}-{}-{}，收益={}，开盘收益={},收盘收益={},最高点收益={}", (i + 1), code, data.getDate(), sellInfo, rate,
                    openRate, closeRate, upRate);
                info += "第" + (i + 1) + "天" + sellInfo + ",收益=" + rate + ",开盘收益=" + openRate + ",收盘收益=" + closeRate
                    + ",最高点收益=" + upRate;
                break;
            }
            //20个点以上，回落到10个点
            if (BigDecimalUtils.isLt(data.getClosePrice(), limitPrice)
                && BigDecimalUtils.isGe(rangeCloseMaxRate, new BigDecimal(20))
                && BigDecimalUtils.isLe(realtimeRate.multiply(new BigDecimal(2)), rangeCloseMaxRate)) {
                sellInfo = "20个点以上回落到10个点左右,止盈";
                log.debug("第{}天-{}-{}-{}，收益={}，开盘收益={},收盘收益={},最高点收益={}", (i + 1), code, data.getDate(), sellInfo, rate,
                    openRate, closeRate, upRate);
                info += "第" + (i + 1) + "天" + sellInfo + ",收益=" + rate + ",开盘收益=" + openRate + ",收盘收益=" + closeRate
                    + ",最高点收益=" + upRate;
                break;
            }
            //冲高回落
            if (Objects.isNull(limitUp)
                && BigDecimalUtils.isGe(rangeCloseMaxRate, new BigDecimal(7))
                && BigDecimalUtils.isLe(realtimeRate, new BigDecimal(3))) {
                sellInfo = "冲高回落,卖出";
                log.debug("第{}天-{}-{}-{}，收益={}，开盘收益={},收盘收益={},最高点收益={}", (i + 1), code, data.getDate(), sellInfo, rate,
                    openRate, closeRate, upRate);
                info += "第" + (i + 1) + "天-" + sellInfo + ",收益=" + rate + ",开盘收益=" + openRate + ",收盘收益=" + closeRate
                    + ",最高点收益=" + upRate;
                break;
            }

            //15日内跌停
            if (i < 15 && StockUtils.isLimitDown(data)) {
                sellInfo = "跌停,卖出";
                log.debug("第{}天-{}-{}-{}，收益={}，开盘收益={},收盘收益={},最高点收益={}", (i + 1), code, data.getDate(), sellInfo, rate,
                    openRate, closeRate, upRate);
                info += "第" + (i + 1) + "天-" + sellInfo + ",收益=" + rate + ",开盘收益=" + openRate + ",收盘收益=" + closeRate
                    + ",最高点收益=" + upRate;
                break;
            }

            ////前3天涨停,拿住
            //if (i <= 2 && isLimitUp(data)) {
            //    sellInfo = i == 2 ? "卖出" : "继续拿着";
            //    log.debug("{}-{}-涨停，{}，收益={},开盘收益={}", code, data.getDate(), sellInfo, closeRate, openRate);
            //    info += "第" + (i + 1) + "天涨停，" + sellInfo + ",收益=" + closeRate + ",开盘收益=" + openRate + ";";
            //    continue;
            //}
            //if (BigDecimalUtils.isGe(realtimeRate, new BigDecimal(40))) {
            //    sellInfo = "涨了大于40个点,止盈";
            //    log.debug("{}-{}-{}，收益={}，开盘收益={},收盘收益={},最高点收益={}", code, data.getDate(), sellInfo, rate, openRate,
            //        closeRate, upRate);
            //    info += "第" + (i + 1) + "天" + sellInfo + ",收益=" + rate + ",开盘收益=" + openRate + ",收盘收益=" + closeRate
            //        + ",最高点收益=" + upRate;
            //    break;
            //}
            if (i == size - 1) {
                log.debug("第{}天-{}-{}-{}，收益={}，开盘收益={},收盘收益={},最高点收益={}", (i + 1), code, data.getDate(), sellInfo, rate,
                    openRate, closeRate, upRate);
                info += "第" + (i + 1) + "天" + sellInfo + ",收益=" + rate + ",开盘收益=" + openRate + ",收盘收益=" + closeRate
                    + ",最高点收益=" + upRate;
                break;
            }

        }
        strategyTradeDTO.setHoldDay(holdIndex + 1);
        strategyTradeDTO.setSellDate(DateUtil.parseDate(sellDate));
        strategyTradeDTO.setSellPrice(sellPrice);
        strategyTradeDTO.setProfitRate(rate);
        strategyTradeDTO.setRangeMaxPrice(rangeMaxPrice);
        strategyTradeDTO.setRealtimeRate(BigDecimalUtils.subStractAndDividePrecent(rangeMaxPrice, buyPrice));
        strategyTradeDTO.setStrategyDescription(info);
        strategyTradeDTO.setStatus("sell");
        strategyTradeDTO.setWinFlag(BigDecimalUtils.isGt(rate, BigDecimal.ZERO) ? "y" : "n");
    }

    private StockDayData getLimipUpDayData(List<StockDayData> subList, int index) {
        int begin = index < 5 ? 0 : index - 5;
        for (int i = begin; i <= index; i++) {
            StockDayData stockDayData = subList.get(i);
            if (StockUtils.isLimitUp(stockDayData)) {
                return stockDayData;
            }
        }
        return null;
    }

    private int filterSignalDayIndex(List<StockDayData> list, StockDayData data, BigDecimal minPrice) {
        if (list.size() < 15) {
            return -1;
        }
        StockDayData afterOneDayData = list.get(0);
        //if (BigDecimalUtils.isGe(afterOneDayData.getRate(), BigDecimal.ZERO)) {
        //    return null;
        //}
        ////最高价比涨停日价格小2个点以下，跳过
        //BigDecimal oneMaxDayRange = afterOneDayData.getMaxPrice().subtract(data.getMaxPrice());
        //BigDecimal oneMaxDayRate = BigDecimalUtils.divideToPrecent(oneMaxDayRange, data.getMaxPrice());
        //if (BigDecimalUtils.isLt(oneMaxDayRate, new BigDecimal(2))) {
        //    return null;
        //}
        StockDayData downDayData = null;
        int index = 0;
        for (int i = 0; i < 7; i++) {
            if (BigDecimalUtils.isLt(list.get(i).getRate(), BigDecimal.ZERO)
                && BigDecimalUtils.isLt(list.get(i + 1).getRate(), BigDecimal.ZERO)
                && BigDecimalUtils.isLt(list.get(i + 2).getRate(), BigDecimal.ZERO)
                && BigDecimalUtils.isLe(list.get(i + 2).getMinPrice(), minPrice)) {
                BigDecimal lowRate = BigDecimalUtils.subStractAndDividePrecent(list.get(i + 2).getMinPrice(), minPrice);
                //跌太多了也不行
                if (BigDecimalUtils.isLt(lowRate, new BigDecimal(-5))) {
                    continue;
                }
                index = i + 2;
                downDayData = list.get(index);
            }
        }
        if (Objects.isNull(downDayData)) {
            return -1;
        }
        return index;
    }

    private StockDayData filterMatchDay(List<StockDayData> list, StockDayData data,
        BigDecimal minPrice, int signalIndex) {

        if (list.size() < 15) {
            return null;
        }
        StockDayData afterOneDayData = list.get(0);
        //if (BigDecimalUtils.isGe(afterOneDayData.getRate(), BigDecimal.ZERO)) {
        //    return null;
        //}
        ////最高价比涨停日价格小2个点以下，跳过
        //BigDecimal oneMaxDayRange = afterOneDayData.getMaxPrice().subtract(data.getMaxPrice());
        //BigDecimal oneMaxDayRate = BigDecimalUtils.divideToPrecent(oneMaxDayRange, data.getMaxPrice());
        //if (BigDecimalUtils.isLt(oneMaxDayRate, new BigDecimal(2))) {
        //    return null;
        //}
        StockDayData downDayData = list.get(signalIndex);
        int size = signalIndex + 5 < list.size() ? signalIndex + 5 : list.size();
        for (int i = signalIndex + 1; i < size; i++) {
            StockDayData dayData = list.get(i);
            if (BigDecimalUtils.isGe(dayData.getClosePrice(), minPrice)) {
                if (BigDecimalUtils.isGt(dayData.getClosePrice(), downDayData.getClosePrice()) && BigDecimalUtils.isGt(
                    dayData.getMaxPrice(), downDayData.getMaxPrice())) {
                    return dayData;
                }
            }
        }
        return null;
    }

}
